﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using MySql.Data;
using MySql.Data.MySqlClient;
using System.Reflection;

namespace Service.Core
{
    class ServNet
    {
        //监听嵌套字
        public Socket listenfd;
        //客户端连接
        public Conn[] conns;
        //最大连接数
        public int maxConn = 50;
        //单例
        public static ServNet instance;

        public ServNet()
        {
            instance = this;
        }

        //获取连接池索引
        public int NewIndex()
        {
            if (conns == null) return -1;
            for (int i = 0; i < conns.Length;i++ )
            {
                if(conns[i] == null)
                {
                    conns[i] = new Conn();
                    return i;
                }else if(conns[i].isUse == false)
                {
                    return i;
                }
            }
            return -1;
        }

        //开启服务，初始化连接池
        public void Start(string host,int port)
        { 
            //连接池
            conns = new Conn[maxConn];
            for (int i = 0; i < maxConn;i++ )
            {
                conns[i] = new Conn();
            }
            //socket
            listenfd = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
            //bind
            IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
            IPEndPoint ipEndPoint = new IPEndPoint(ipAddress,1234);
            listenfd.Bind(ipEndPoint);
            //listen
            listenfd.Listen(maxConn);
            //accept 异步接收
            listenfd.BeginAccept(AcceptCb,null);
            Console.WriteLine("service success");
        }

        #region 回调
        //回调 1给新的连接分配conn，2异步接收客户端数据，3再次调用beginAccept
        public void AcceptCb(IAsyncResult ar)
        {
            try
            {
                Socket socket = listenfd.EndAccept(ar);
                int index = NewIndex();
                if (index < 0)
                {
                    //不可连接
                    socket.Close();
                }
                else
                {
                    Conn conn = conns[index];
                    conn.Init(socket);
                    string adr = conn.GetAdress();
                    Console.WriteLine("connect ::"+adr);
                    //异步接收客户端数据
                    conn.socket.BeginReceive(conn.readBuff, conn.buffCount, conn.BuffRemain(), SocketFlags.None, ReceiveCb, conn);
                    //再次调用
                    listenfd.BeginAccept(AcceptCb, null);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }

        //回调 1接收并处理消息，2分包处理，3再次接收
        public void ReceiveCb(IAsyncResult ar)
        {
            //获取BeginReceive（）传入的conn对象
            Conn conn = (Conn)ar.AsyncState;
            lock (conn)
            {
                try
                {
                    //获取接收字节数
                    int count = conn.socket.EndReceive(ar);
                    if (count < 0)
                    {
                        conn.Close();
                    }
                    //数据处理 分包粘包处理
                    conn.buffCount += count;
                    ProcessData(conn);
                    //继续接收
                    conn.socket.BeginReceive(conn.readBuff, conn.buffCount, conn.BuffRemain(), SocketFlags.None, ReceiveCb, conn);

                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
            }
        }
        #endregion

        #region 分包粘包处理
        private void ProcessData(Conn conn)
        {
            if (conn.buffCount < sizeof(Int32)) return;
            //消息长度
            Array.Copy(conn.readBuff, conn.lenBytes, sizeof(Int32));//把readBuff前四个字节复制到lenBytes中
            conn.msglength = BitConverter.ToInt32(conn.lenBytes,0);//获取消息长度
            Console.WriteLine("message length::"+conn.msglength+" total ::"+conn.lenBytes.ToArray()); 
            if(conn.buffCount < conn.msglength+sizeof(Int32)) return;
            
            //处理消息
            string str = System.Text.Encoding.UTF8.GetString(conn.readBuff, sizeof(Int32), conn.msglength);
            Console.WriteLine("message ::"+str);
            Send(conn,str);

            //清除已经处理的消息
            int count = conn.buffCount - conn.msglength - sizeof(Int32);
            Array.Copy(conn.readBuff,sizeof(Int32)+conn.msglength,conn.readBuff,0,count);
            conn.buffCount = count;
            if (conn.buffCount > 0)
            {
                ProcessData(conn);
            }
            //str = conn.GetAdress() + str;
            //byte[] bytes = System.Text.Encoding.Default.GetBytes(str);
            //for (int i = 0; i < conns.Length; i++)
            //{
            //    conns[i].socket.Send(bytes);
            //}
        }
        #endregion

        public void Send(Conn conn,string str)
        {
            byte[] bytes = System.Text.Encoding.UTF8.GetBytes(str);
            byte[] length = BitConverter.GetBytes(bytes.Length);
            byte[] sendBuff = length.Concat(bytes).ToArray();

            conn.socket.BeginSend(sendBuff,0,sendBuff.Length,SocketFlags.None,null,null);
        }
    }
}
